package com.xb.chain.block;

import com.xb.chain.entity.Block;
import com.xb.chain.entity.Result;
import com.xb.chain.pow.ProofOfWork;
import com.xb.chain.transaction.Transaction;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

/**
 * @author xiaobin
 * @date 2020/2/19 16:45
 * @desc
 */
@Component
@Slf4j
public class BlockChain extends AbstractBlockChain implements InitializingBean {

    /**
     * 添加新区块
     */
    @Override
    public Block mineBlock(List<Transaction> transactions) {
        Result result = this.validataBlockChain();
        if (result.getCode() == 0) {
            Block block = new Block(list.get(list.size()-1).getBlockHash(), transactions == null ? new ArrayList<>() : transactions);
            Block generateBlock = generateBlock(block);
            this.list.add(generateBlock);
            return generateBlock;
        }
        return null;

    }


    /**
     * 转账
     */
    public Transaction transfer(String from, String to, BigDecimal value) {
        // 判断整条链是否被修改过数据
        Result result = this.validataBlockChain();
        if (result.getCode() == 0) {
            // 判断是否有余额
            BigDecimal balance = getBalance(from);
            if (balance.compareTo(value) >= 0) {
                return new Transaction(from, to, value);
            }
        }
        // 丢弃
        return null;

    }

    @Override
    public BigDecimal getBalance(String address) {
        BigDecimal balance = BigDecimal.ZERO;
        for (Block block : this.list) {
            BigDecimal enterBalance = getEnterBalance(block.getTransactions(), address);
            BigDecimal outBalance = getOutBalance(block.getTransactions(), address);
            balance = balance.add(enterBalance).subtract(outBalance);
        }
        return balance;
    }

    /**
     * 获取口袋的总资金（不包括转账的）
     *
     * @return
     */
    private BigDecimal getEnterBalance(List<Transaction> transactions, String address) {
        return new BigDecimal(transactions.stream().filter((item) -> {
            return item.to.equals(address);
        }).map((item) -> {
            return item.value;
        }).mapToDouble(BigDecimal::doubleValue).sum());
    }

    /**
     * 获取转账出去总资金（不包括收到的）
     *
     * @return
     */
    private BigDecimal getOutBalance(List<Transaction> transactions, String address) {
        return new BigDecimal(transactions.stream().filter((item) -> {
            return item.from.equals(address);
        }).map((item) -> {
            return item.value;
        }).mapToDouble(BigDecimal::doubleValue).sum());
    }


    @Override
    public void afterPropertiesSet() throws Exception {
        Block block = this.startBlock();
        log.info("创世区块：" + block);
    }
}
